﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Sustainalytics.ESGRatings.BusinessLogic.ESGClient;
using Sustainalytics.MongoDB.Extensions;
using Sustainalytics.ESGRatings.DataLayer;
using System.Configuration;
using MongoDB.Driver;
using Sustainalytics.Entities.ESGRatings.Historical;
using Sustainalytics.ESGRatings.Computing.Entities.ESG;
using Sustainalytics.ESG.Entities;

namespace Sustainalytics.ESG.HistoricalDataComputation
{
    class Program
    {
        static void Main(string[] args)
        {
            var historicalDataConnectionString = ConfigurationManager.ConnectionStrings["RPHistoricalDataSet"].ConnectionString;
            var historicalWriteConnectionString = ConfigurationManager.ConnectionStrings["DWArchiveWrite"].ConnectionString;

            var dwArchiveDataConnectionString = ConfigurationManager.ConnectionStrings["DWArchive"].ConnectionString;
            var esgComputing = System.Configuration.Abstractions.ConfigurationManager.Instance.AppSettings["ComputationServiceAddress"];



            var datasetsCollection = MongoFactory.GetCollectionFromDatabase<HistoricalDataSet>(historicalDataConnectionString);
            var companyDataCollection = MongoFactory.GetCollectionFromDatabase<DSWeightMatrix>(historicalDataConnectionString);

            var esgProfilesCollection = MongoFactory.GetCollectionFromDatabase<ESGProfile>(dwArchiveDataConnectionString);
            var writeCollection = MongoFactory.GetCollectionFromDatabase<HistoricalData>(historicalWriteConnectionString);

            writeCollection.DeleteManyAsync(x => true).Wait();

            var esgProfiles = GetESGProfilesAsync(esgProfilesCollection).Result;

            var historicalIds = GetHistoricalDataSetsAsync(datasetsCollection).Result;

            foreach (var id in historicalIds)
            {
                Console.WriteLine($"{id.Item1} - {id.Item2}");
                var date = id.Item2;
                var esgProfile = esgProfiles.FirstOrDefault(x => x.ProcessedDate.Year == date.Year && x.ProcessedDate.Month == date.Month);
                if (esgProfile != null)
                {
                    esgProfile.Instance.CompanyType = Sustainalytics.Entities.ESGRatings.CompanyTypeEnum.Combined;
                    esgProfile.Instance.TemplateType = Sustainalytics.Entities.ESGRatings.TemplateTypeEnum.Combined;
                    using (var esgClient = new ESGClient(esgComputing))
                    {
                        var setId = esgClient.LoadDataAsync(id.Item1).Result;
                        if (setId != Guid.Empty)
                        {
                            var computingClient = new ESGRatingsComputationsClient(esgComputing, esgProfile.Instance, setId);
                            var adapterTask = computingClient.GetRatingsAsync().Result;
                            var companies = GetCompaniesAsync(companyDataCollection, setId, esgProfile.Instance.MatrixId).Result;
                            foreach (var company in companies)
                            {
                                var esgData = adapterTask.GetEsgData(company);
                                if (esgData != null)
                                {
                                    var companyHistoricalData = new HistoricalData(id.Item2, company)
                                    {
                                        OverallScore = esgData.Score,
                                        OverallPercentile = esgData.Percentile,
                                        EScore = esgData.EnvironmentScore,
                                        EPercentile = esgData.EnvironmentPercentile,
                                        SScore = esgData.SocialScore,
                                        SPercentile = esgData.SocialPercentile,
                                        GScore = esgData.GovernanceScore,
                                        GPercentile = esgData.GovernancePercentile,
                                        SetId = setId,
                                        Id = Guid.NewGuid()

                                    };

                                    writeCollection.ReplaceOneAsync(x => x.CompanyId == companyHistoricalData.CompanyId && x.SetId == companyHistoricalData.SetId, companyHistoricalData, new UpdateOptions { IsUpsert = true }).Wait();
                                }
                            }
                        }

                        esgClient.Clean().Wait();

                    }
                }
            }

            Console.Write("Finished");

            Console.ReadKey();
        }


        private static async Task<IEnumerable<Guid>> GetCompaniesAsync(IMongoCollection<DSWeightMatrix> corporateDataCollection, Guid setId, Guid matrixId)
        {
            var matrix = await corporateDataCollection.Find(x => x.SetId == setId && x.Instance.MatrixId == matrixId).Project(x => x.Instance).FirstOrDefaultAsync().ConfigureAwait(false);

            if (matrix != null)
            {
                return matrix.CompaniesWeights.Where(x => x.ProfileHasEsgResearch).Select(x => x.CompanyId);
            }
            return Enumerable.Empty<Guid>();
        }

        private static async Task<IEnumerable<ESGProfile>> GetESGProfilesAsync(IMongoCollection<ESGProfile> datasetsCollection)
        {
            var historicalDataSets = await datasetsCollection.Find(x => true).ToListAsync().ConfigureAwait(false);
            var lastYear = new DateTime(DateTime.Today.Year - 1, DateTime.Today.Month, 1, 0, 0, 0, DateTimeKind.Utc);
            var ids = historicalDataSets.GroupBy(x => x.ProcessedDate).Select(x => x.First()).Where(x => x.ProcessedDate >= lastYear).Select(x => x);
            return ids;
        }


        private static async Task<IEnumerable<Tuple<Guid, DateTime>>> GetHistoricalDataSetsAsync(IMongoCollection<HistoricalDataSet> datasetsCollection)
        {
            var today = DateTime.Today;

            var dates = new DateTime(today.Year, today.Month, 1, 0, 0, 0, DateTimeKind.Utc).AddMonths(-13);
            var historicalDataSets = await datasetsCollection.Find(x => x.ToBePreserved == true && x.CreationDate >= dates).SortByDescending(x => x.CreationDate).ToListAsync().ConfigureAwait(false);
            var selectedHistoricalDataSets = historicalDataSets.GroupBy(x => x.SetName).Select(x => x.First());
            return selectedHistoricalDataSets.Select(set => new Tuple<Guid, DateTime>(set.Id, set.CreationDate));
        }
    }


}
